<script setup lang="ts">
import type {
  AttachmentsProps,
  BubbleListProps,
  ConversationsProps,
  PromptsProps,
  RequestFn,
} from 'ant-design-x-vue';

import type { VNode } from 'vue';

import { computed, h, ref, watch } from 'vue';

import {
  CloudUploadOutlined,
  PaperClipOutlined,
  PlusOutlined,
} from '@ant-design/icons-vue';
import { Badge, Button, Flex, Space, theme, Typography } from 'ant-design-vue';
import {
  Attachments,
  Bubble,
  Conversations,
  Prompts,
  Sender,
  useXAgent,
  useXChat,
  Welcome,
  XStream,
} from 'ant-design-x-vue';

// 定义组件名
defineOptions({ name: 'PlaygroundIndependentSetup' });

// 使用 Ant Design 的主题 token
const { token } = theme.useToken();

// 计算样式对象，包含布局、菜单、会话、聊天等样式
const styles = computed(() => {
  return {
    layout: {
      width: '100%',
      'min-width': '1000px',
      height: '722px',
      'border-radius': `${token.value.borderRadius}px`,
      display: 'flex',
      background: `${token.value.colorBgContainer}`,
      'font-family': `AlibabaPuHuiTi, ${token.value.fontFamily}, sans-serif`,
    },
    menu: {
      background: `${token.value.colorBgLayout}80`,
      width: '280px',
      height: '100%',
      display: 'flex',
      'flex-direction': 'column',
    },
    conversations: {
      padding: '0 12px',
      flex: 1,
      'overflow-y': 'auto',
    },
    chat: {
      height: '100%',
      width: '100%',
      'max-width': '700px',
      margin: '0 auto',
      'box-sizing': 'border-box',
      display: 'flex',
      'flex-direction': 'column',
      padding: `${token.value.paddingLG}px`,
      gap: '16px',
    },
    messages: {
      flex: 1,
    },
    placeholder: {
      'padding-top': '32px',
      'text-align': 'left',
      flex: 1,
    },
    sender: {
      'box-shadow': token.value.boxShadow,
    },
    logo: {
      display: 'flex',
      height: '72px',
      'align-items': 'center',
      'justify-content': 'start',
      padding: '0 24px',
      'box-sizing': 'border-box',
    },
    'logo-img': {
      width: '24px',
      height: '24px',
      display: 'inline-block',
    },
    'logo-span': {
      display: 'inline-block',
      margin: '0 8px',
      'font-weight': 'bold',
      color: token.value.colorText,
      'font-size': '16px',
    },
    addBtn: {
      background: '#1677ff0f',
      border: '1px solid #1677ff34',
      width: 'calc(100% - 24px)',
      margin: '0 12px 24px 12px',
    },
  } as const;
});

// 模拟异步操作的 sleep 函数

/**
 * 渲染标题
 * @param icon - 图标 VNode
 * @param title - 标题文本
 * @returns 返回包含图标和标题的 Space 组件
 */
function renderTitle(icon: VNode, title: string) {
  return h(Space, { align: 'start' }, [icon, h('span', title)]);
}

// 默认的会话项
const defaultConversationsItems = [
  {
    key: '0',
    label: 'What is Ant Design X?',
  },
];

// 占位符提示词项

// 发送者提示词项
const senderPromptsItems: PromptsProps['items'] = [
  // {
  //   key: '1',
  //   description: 'Hot Topics',
  //   icon: h(FireOutlined, { style: { color: '#FF4D4F' } }),
  // },
  // {
  //   key: '2',
  //   description: 'Design Guide',
  //   icon: h(ReadOutlined, { style: { color: '#1890FF' } }),
  // },
];

// 定义 AI 和本地用户的角色样式
const roles: BubbleListProps['roles'] = {
  ai: {
    placement: 'start',
    typing: { step: 5, interval: 20 },
    styles: {
      content: {
        borderRadius: '16px',
      },
    },
  },
  local: {
    placement: 'end',
    variant: 'shadow',
  },
};

// ==================== State ====================
const headerOpen = ref(false); // 控制附件面板的展开状态
const content = ref(''); // 输入框内容
const conversationsItems = ref(defaultConversationsItems); // 会话项列表
const activeKey = ref(defaultConversationsItems[0].key); // 当前激活的会话项 key
const attachedFiles = ref<AttachmentsProps['items']>([]); // 附件列表
const agentRequestLoading = ref(false); // 请求加载状态

// ==================== Runtime ====================

function readableStream() {
  return new ReadableStream({
    async start(controller) {
      try {
        const response = await fetch(
          'http://localhost:5666/api/alibaba/chat/stream',
          {
            method: 'POST', // 根据后端要求，可能需要改为其他方法
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ content: '你好' }),
          },
        );

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const reader = response.body.getReader();
        const decoder = new TextDecoder('utf-8');

        while (true) {
          const { done, value } = await reader.read();

          if (done) {
            controller.close();
            break;
          }
          const data = decoder.decode(value);
          controller.enqueue(new TextEncoder().encode(data));
        }
      } catch (error) {
        console.error('Error connecting to SSE:', error);
      }
    },
  });
}

// 请求
const handleRequest: RequestFn<string> = async (info, callbacks) => {
  const { message } = info;
  const { onSuccess, onUpdate } = callbacks;
  agentRequestLoading.value = true;
  let content = ''

  for await (const chunk of XStream({ readableStream: readableStream() })) {
    console.log(chunk, 'chunk');
    content+=chunk.data
    onUpdate(chunk.data);
  }
  agentRequestLoading.value = false;
  onSuccess(content);


};

// 使用 XAgent 进行请求处理
const [agent] = useXAgent({
  request: handleRequest,
});

// 使用 XChat 进行聊天管理
const { onRequest, messages, setMessages } = useXChat({
  agent: agent.value,
});

// 监听 activeKey 变化，重置消息列表
watch(
  activeKey,
  () => {
    if (activeKey.value !== undefined) {
      setMessages([]);
    }
  },
  { immediate: true },
);

// ==================== Event ====================
/**
 * 提交消息
 * @param nextContent - 提交的内容
 */
function onSubmit(nextContent: string) {
  if (!nextContent) return;
  onRequest(nextContent);
  content.value = '';
}

/**
 * 提示词项点击事件
 * @param info - 提示词项信息
 */
const onPromptsItemClick: PromptsProps['onItemClick'] = (info) => {
  onRequest(info.data.description as string);
};

/**
 * 添加新会话
 */
function onAddConversation() {
  conversationsItems.value = [
    ...conversationsItems.value,
    {
      key: `${conversationsItems.value.length}`,
      label: `新会话`,
    },
  ];
  activeKey.value = `${conversationsItems.value.length}`;
}

/**
 * 会话项点击事件
 * @param key - 会话项 key
 */
const onConversationClick: ConversationsProps['onActiveChange'] = (key) => {
  activeKey.value = key;
};

/**
 * 附件变化事件
 * @param info - 附件信息
 */
const handleFileChange: AttachmentsProps['onChange'] = (info) =>
  (attachedFiles.value = info.fileList);

// ==================== Nodes ====================
// 计算占位符节点
const placeholderNode = computed(() =>
  h(
    Space,
    { direction: 'vertical', size: 16, style: styles.value.placeholder },
    [
      h(Welcome, {
        variant: 'borderless',
        icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
        title: '你好, 欢迎使用AI小助手',
        // description: "我是基于Spring AI ",
        // extra: h(Space, {}, [h(Button, { icon: h(ShareAltOutlined) }), h(Button, { icon: h(EllipsisOutlined) })]),
      }),
      // h(
      //   Prompts,
      //   {
      //     title: "Do you want?",
      //     items: placeholderPromptsItems,
      //     styles: {
      //       list: {
      //         width: '100%',
      //       },
      //       item: {
      //         flex: 1,
      //       },
      //     },
      //     onItemClick: onPromptsItemClick,
      //   }
      // )
    ],
  ),
);

// 计算消息项
const items = computed<BubbleListProps['items']>(() => {
  if (messages.value.length === 0) {
    return [{ content: placeholderNode, variant: 'borderless' }];
  }
  return messages.value.map(({ id, message, status }) => ({
    key: id,
    loading: status === 'loading',
    role: status === 'local' ? 'local' : 'ai',
    content: message,
  }));
});
</script>

<template>
  <div :style="styles.layout">
    <div :style="styles.menu">
      <!-- 🌟 Logo -->
      <div :style="styles.logo">
        <img
          src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
          draggable="false"
          alt="logo"
          :style="styles['logo-img']"
        />
        <span :style="styles['logo-span']">Ant Design X Vue</span>
      </div>

      <!-- 🌟 添加会话 -->
      <Button type="link" :style="styles.addBtn" @click="onAddConversation">
        <PlusOutlined />
        开启新对话
      </Button>

      <!-- 🌟 会话管理 -->
      <Conversations
        :items="conversationsItems"
        :style="styles.conversations"
        :active-key="activeKey"
        @active-change="onConversationClick"
      />
    </div>

    <div :style="styles.chat">
      <!-- 🌟 消息列表 -->
      <Bubble.List :items="items" :roles="roles" :style="styles.messages" />

      <!-- 🌟 提示词 -->
      <Prompts :items="senderPromptsItems" @item-click="onPromptsItemClick" />

      <!-- 🌟 输入框 -->
      <Sender
        :value="content"
        :style="styles.sender"
        :loading="agentRequestLoading"
        @submit="onSubmit"
        @change="(value) => (content = value)"
      >
        <template #prefix>
          <Badge :dot="attachedFiles.length > 0 && !headerOpen">
            <Button type="text" @click="() => (headerOpen = !headerOpen)">
              <template #icon>
                <PaperClipOutlined />
              </template>
            </Button>
          </Badge>
        </template>

        <template #header>
          <Sender.Header
            title="Attachments"
            :open="headerOpen"
            :styles="{ content: { padding: 0 } }"
            @open-change="(open) => (headerOpen = open)"
          >
            <Attachments
              :before-upload="() => false"
              :items="attachedFiles"
              @change="handleFileChange"
            >
              <template #placeholder="type">
                <Flex
                  v-if="type && type.type === 'inline'"
                  align="center"
                  justify="center"
                  vertical
                  gap="2"
                >
                  <Typography.Text style="font-size: 30px; line-height: 1">
                    <CloudUploadOutlined />
                  </Typography.Text>
                  <Typography.Title
                    :level="5"
                    style="margin: 0; font-size: 14px; line-height: 1.5"
                  >
                    Upload files
                  </Typography.Title>
                  <Typography.Text type="secondary">
                    Click or drag files to this area to upload
                  </Typography.Text>
                </Flex>
                <Typography.Text v-if="type && type.type === 'drop'">
                  Drop file here
                </Typography.Text>
              </template>
            </Attachments>
          </Sender.Header>
        </template>
      </Sender>
    </div>
  </div>
</template>
